import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
import { join } from "node:path";
import { TYPES } from "@main/shared/types";
import logger from "@shared/logger/main-logger";
import { app } from "electron";
import { inject, injectable } from "inversify";
import {
  CommunicationWay,
  ServiceHandler,
  ServiceRegister,
} from "../../../shared/reflect";
import type { ShellService } from "../../shell-service";

interface LogEntry {
  timestamp: string;
  level: string;
  message: string;
  context?: string;
}

interface LogFile {
  date: string;
  level: string;
  path: string;
  size: number;
  entries: LogEntry[];
}

@ServiceRegister(TYPES.FilePreviewService)
@injectable()
export class FilePreviewService {
  constructor(@inject(TYPES.ShellService) private shellService: ShellService) {}

  @ServiceHandler(CommunicationWay.RENDERER_TO_MAIN__TWO_WAY)
  async previewFileByPath(
    _event: Electron.IpcMainInvokeEvent,
    filePath: string,
  ): Promise<{ success: boolean; error?: string }> {
    try {
      if (!existsSync(filePath)) {
        return { success: false, error: "file-not-found" };
      }

      // 使用 ShellService 打开文件
      const result = await this.shellService.openPath(_event, filePath);

      if (result) {
        // 如果有错误信息，说明打开失败
        return { success: false, error: result };
      }

      return { success: true };
    } catch (error) {
      logger.error("FilePreviewService: Error previewing file by path", {
        error,
      });
      return {
        success: false,
        error: error instanceof Error ? error.message : "Unknown error",
      };
    }
  }

  @ServiceHandler(CommunicationWay.RENDERER_TO_MAIN__TWO_WAY)
  async getLogFiles(_event: Electron.IpcMainInvokeEvent): Promise<LogFile[]> {
    try {
      const userData = app.getPath("userData");
      const logsDir = join(userData, "logs");

      if (!existsSync(logsDir)) {
        return [];
      }

      const logFiles: LogFile[] = [];
      const monthDirs = readdirSync(logsDir, { withFileTypes: true })
        .filter(
          (dirent) => dirent.isDirectory() && /^\d{4}-\d{2}$/.test(dirent.name),
        )
        .map((dirent) => dirent.name)
        .sort()
        .reverse(); // Latest first

      for (const monthDir of monthDirs) {
        const monthPath = join(logsDir, monthDir);
        const dayDirs = readdirSync(monthPath, { withFileTypes: true })
          .filter(
            (dirent) => dirent.isDirectory() && /^\d{2}$/.test(dirent.name),
          )
          .map((dirent) => dirent.name)
          .sort()
          .reverse(); // Latest first

        for (const dayDir of dayDirs) {
          const dayPath = join(monthPath, dayDir);
          const date = `${monthDir}-${dayDir}`;

          const logLevels = ["error", "warn", "info", "debug"];
          for (const level of logLevels) {
            const logFilePath = join(dayPath, `${level}.log`);
            if (existsSync(logFilePath)) {
              const stats = statSync(logFilePath);
              logFiles.push({
                date,
                level,
                path: logFilePath,
                size: stats.size,
                entries: [], // Will be loaded separately
              });
            }
          }
        }
      }

      return logFiles;
    } catch (error) {
      logger.error("FilePreviewService: Error getting log files", { error });
      return [];
    }
  }

  @ServiceHandler(CommunicationWay.RENDERER_TO_MAIN__TWO_WAY)
  async readLogFile(
    _event: Electron.IpcMainInvokeEvent,
    date: string,
    level: string,
  ): Promise<LogFile | null> {
    try {
      const userData = app.getPath("userData");
      const [yearMonth, day] =
        date.split("-").length === 3
          ? [date.substring(0, 7), date.substring(8)]
          : ["", ""];

      if (!yearMonth || !day) {
        return null;
      }

      const logFilePath = join(
        userData,
        "logs",
        yearMonth,
        day,
        `${level}.log`,
      );

      if (!existsSync(logFilePath)) {
        return null;
      }

      const content = readFileSync(logFilePath, "utf8");
      const lines = content.split("\n").filter((line) => line.trim());
      const entries: LogEntry[] = [];

      for (const line of lines) {
        const match = line.match(/^\[([^\]]+)\] (\w+): (.+?)(?:\s+(\{.+\}))?$/);
        if (match) {
          const [, timestamp, logLevel, message, context] = match;
          entries.push({
            timestamp,
            level: logLevel,
            message,
            context: context || undefined,
          });
        }
      }

      const stats = statSync(logFilePath);
      return {
        date,
        level,
        path: logFilePath,
        size: stats.size,
        entries,
      };
    } catch (error) {
      logger.error("FilePreviewService: Error reading log file", {
        error,
        date,
        level,
      });
      return null;
    }
  }

  @ServiceHandler(CommunicationWay.RENDERER_TO_MAIN__TWO_WAY)
  async openLogDirectory(
    _event: Electron.IpcMainInvokeEvent,
  ): Promise<{ success: boolean; error?: string }> {
    try {
      const userData = app.getPath("userData");
      const logsDir = join(userData, "logs");

      if (!existsSync(logsDir)) {
        return { success: false, error: "Log directory does not exist" };
      }

      // 使用 ShellService 打开文件夹
      const result = await this.shellService.openPath(_event, logsDir);

      if (result) {
        // 如果有错误信息，说明打开失败
        return { success: false, error: result };
      }

      return { success: true };
    } catch (error) {
      logger.error("FilePreviewService: Error opening log directory", {
        error,
      });
      return {
        success: false,
        error: error instanceof Error ? error.message : "Unknown error",
      };
    }
  }

  @ServiceHandler(CommunicationWay.RENDERER_TO_MAIN__TWO_WAY)
  async clearLogs(
    _event: Electron.IpcMainInvokeEvent,
  ): Promise<{ success: boolean; error?: string }> {
    try {
      const { cleanupLogs } = await import("@shared/logger/main-logger");
      cleanupLogs();
      return { success: true };
    } catch (error) {
      logger.error("FilePreviewService: Error clearing logs", { error });
      return {
        success: false,
        error: error instanceof Error ? error.message : "Unknown error",
      };
    }
  }
}
